package com.baomidou.springwind.pojo;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.springwind.baidu.Geocoder;
import com.baomidou.springwind.entity.NetworkDelivery;

import java.math.BigDecimal;
import java.util.*;

/**
 * 一级配送中心选址构造对象
 *
 * @Author demo
 * @Date 2017-8-6
 */
public class SiteSelectionBuilder {

    /**
     * 调节系数
     */
    private Double adjust1 = 0.5D;

    /**
     * 调节系数
     */
    private Double adjust2 = 2D;

    /**
     * 一级配送中心
     */
    private List<NetworkDelivery> firstSites;

    /**
     * 二级配送中心
     */
    private List<NetworkDelivery> secondSites;


    public SiteSelectionBuilder(List<NetworkDelivery> firstSites, List<NetworkDelivery> secondSites) {
        this.firstSites = firstSites;
        this.secondSites = secondSites;
    }

    public List<SiteSelection> build() {
        BigDecimal avgOrder = step1();
        List<SiteDistance> combSiteList = step2(avgOrder);
        List<SiteSelection> siteSelectionList = step4(combSiteList);
        List<NetworkDelivery> oldSiteList = new ArrayList<NetworkDelivery>(firstSites);
        for (int i = 0; i < siteSelectionList.size(); i++) {
            SiteDistance sd = combSiteList.get(i);
            SiteSelection ss = siteSelectionList.get(i);
            ss.addAllChildren(getChildSite(sd.site1.getId()));
            ss.addAllChildren(getChildSite(sd.site2.getId()));
            oldSiteList.remove(sd.site1);
            oldSiteList.remove(sd.site2);
            ss.setOlder(true);
        }
        for (NetworkDelivery delivery : oldSiteList) {
            SiteSelection sd = SiteSelection.transform(delivery);
            sd.setChildren(getChildSite(delivery.getId()));
            siteSelectionList.add(sd);
        }
        return siteSelectionList;
    }

    public List<SiteSelection> getOrginSiteList() {
        List<SiteSelection> siteSelectionList = new ArrayList<SiteSelection>(firstSites.size());
        for (NetworkDelivery delivery : firstSites) {
            SiteSelection sd = SiteSelection.transform(delivery);
            sd.setChildren(getChildSite(delivery.getId()));
            siteSelectionList.add(sd);
        }
        return siteSelectionList;
    }


    /**
     * 计算平均订单量
     *
     * @return
     */
    private BigDecimal step1() {
        BigDecimal total = new BigDecimal(0);
        for (NetworkDelivery delivery : firstSites) {
            total = total.add(delivery.getOrderQuantity());
        }
        return total.divide(new BigDecimal(firstSites.size()), BigDecimal.ROUND_HALF_EVEN);
    }

    /**
     * 生成组合
     *
     * @return
     */
    private List<SiteDistance> step2(BigDecimal avgOrder) {
        List<NetworkDelivery> s1 = new ArrayList<NetworkDelivery>();
        List<NetworkDelivery> s2 = new ArrayList<NetworkDelivery>();
        List<NetworkDelivery> s3 = new ArrayList<NetworkDelivery>();
        BigDecimal θ1 = avgOrder.multiply(new BigDecimal(adjust1));
        BigDecimal θ2 = avgOrder.multiply(new BigDecimal(adjust2));
        for (NetworkDelivery delivery : firstSites) {
            if (delivery.getOrderQuantity().compareTo(θ1) < 0) {
                s1.add(delivery);
            } else if (delivery.getOrderQuantity().compareTo(θ2) > 0) {
                s3.add(delivery);
            } else {
                s2.add(delivery);
            }
        }
        List<SiteDistance> siteDistanceSet = new ArrayList<SiteDistance>();
        Set<Long> ids = new HashSet<Long>();
        for (int i = 0; i < s1.size(); i++) {
            for (int j = i + 1; j < s1.size(); j++) {
                siteDistanceSet.add(new SiteDistance(s1.get(i), s1.get(j)));
            }
            for (NetworkDelivery delivery : s2) {
                siteDistanceSet.add(new SiteDistance(s1.get(i), delivery));
            }
            ids.add(s1.get(i).getId());
        }
        Collections.sort(siteDistanceSet, new Comparator<SiteDistance>() {
            @Override
            public int compare(SiteDistance o1, SiteDistance o2) {
                return o1.disance.compareTo(o2.disance);
            }
        });
        List<SiteDistance> selectedList = new ArrayList<SiteDistance>();
        Set<NetworkDelivery> exsits = new HashSet<NetworkDelivery>();
        for (SiteDistance sd : siteDistanceSet) {
            if (ids.size() == 0) {
                break;
            }
            if (exsits.contains(sd.site1) || exsits.contains(sd.site2)) {
                continue;
            }
            selectedList.add(sd);
            exsits.add(sd.site1);
            exsits.add(sd.site2);
            ids.remove(sd.site1.getId());
        }
        return selectedList;
    }

    /**
     * 备选配送中心
     *
     * @param selectedList
     */
    private List<SiteSelection> step4(List<SiteDistance> selectedList) {
        List<SiteSelection> siteSelectionList = new ArrayList<SiteSelection>(selectedList.size());
        for (SiteDistance distance : selectedList) {
            List<NetworkDelivery> siteCoverList = new ArrayList<NetworkDelivery>();
            for (NetworkDelivery delivery : secondSites) {
                if (delivery.getpId().equals(distance.site1.getId()) || delivery.getpId().equals(distance.site2.getId())) {
                    siteCoverList.add(delivery);
                }
            }
            BigDecimal total = new BigDecimal(0);
            BigDecimal totalCX = new BigDecimal(0);
            BigDecimal totalCY = new BigDecimal(0);
            for (NetworkDelivery delivery : siteCoverList) {
                totalCX = totalCX.add(delivery.getCoordinateX().multiply(delivery.getOrderQuantity()));
                totalCY = totalCY.add(delivery.getCoordinateY().multiply(delivery.getOrderQuantity()));
                total = total.add(delivery.getOrderQuantity());
            }
            BigDecimal centerCX = totalCX.divide(total, 10, BigDecimal.ROUND_HALF_EVEN);
            BigDecimal centerCY = totalCY.divide(total, 10, BigDecimal.ROUND_HALF_EVEN);
            JSONObject result = Geocoder.getAddressComponent(centerCX, centerCY);
            System.out.println(result.getJSONObject("addressComponent"));
            siteSelectionList.add(new SiteSelection(result.getJSONObject("addressComponent").getString("city"), centerCX, centerCY, distance.site1.getOrderQuantity().add(distance.site2.getOrderQuantity()),0L));
        }
        return siteSelectionList;
    }

    /**
     * 获取一级配送中心覆盖的二级配送中心
     *
     * @return
     */
    private List<SiteSelection> getChildSite(Long pid) {
        List<SiteSelection> children = new ArrayList<SiteSelection>();
        for (NetworkDelivery delivery : secondSites) {
            if (pid.equals(delivery.getpId())) {
                children.add(new SiteSelection(delivery.getName(), delivery.getCoordinateX(), delivery.getCoordinateY(), delivery.getOrderQuantity(),delivery.getLnglatId()));
            }
        }
        return children;
    }
}
